/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/
// 1. 传入执行函数fn， 参数resolve,reject
// 2. 需要三种状态、内部需要成功value、失败reason
// 3. 需要实现then方法，两个回调成功函数、失败函数。
	//   需要处理异步pending情况，
	//   需要处理链式调用 返回promise
	//   多个then回调执行
// 处理链式调用
	// 普通值、promise,除自身以为防止promise循环调用
	// 处理方式代码需要异步之执行

//错误处理
	// 执行器错误处理
	// then回调错误处理

// then回调函数参数默认处理，参数可选

// all方法
	// 传入promise list,元素也可是普通值
	// 全部成功才返回，返回结果顺序与list一致 请求并发，

// resolve方法
	// 判断是否是promise
	// 	是promise接返回
	// 	否包装返回promise

// reject方法逻辑同上

// finally 
	// 成功失败都执行
	// 链式调用
	// 要等待回调内部返回的promise

// catch 
	// 失败执行
	// 链式调用

// const { reject } = require("lodash");
// const MyPromise = require("../../../../Downloads/01-01-study-materials/01-01-codes/01-01-03-01-my-promise/myPromise");


const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
	constructor (executor) {
		try {
			executor(this.resolve, this.reject);
		} catch (e) {
			this.reject(e)
		}
	}
	status = PENDING;
	reason = undefined;
	value = undefined;
	// successCallback = ''
	// failCallback = ''
	successCallback = []
	failCallback = []

	resolve  = value => {
		// 状态只能从pending->resolve
		if (this.status !== PENDING) return;
		this.status = FULFILLED;
		this.value = value;
		// 处理单个then回调
		// this.successCallback(this.value)
		//多个then回调执行、从前往后执行
		while(this.successCallback.length) this.successCallback.shift()(this.value)

	}
	

	reject = reason => {
		// 状态只能从pending->reject
		if (this.status !== PENDING) return
		this.status = REJECTED;
		this.reason = reason;
		// this.failCallback(this.reason)
		while(this.failCallback.length) this.failCallback.shift()(this.reason)
	}

	finally = (callback)  => {
		return this.then(value => {
			return MyPromise.resolve(callback()).then(() => value);
			}, reason => {
			return MyPromise.resolve(callback()).then(() => { throw reason })
		})
	}

	catch (failCallback) {
		return this.then(undefined, failCallback)
	}

	then  (successCallback, failCallback)  {
		//处理链式调用返回promise 
		successCallback = successCallback ? successCallback : value => value;
		failCallback = failCallback ? failCallback: reason => { throw reason };
		let p = new MyPromise((resolve, reject) => {
			if (this.status === FULFILLED) {
				setTimeout(() => {
					try {
						let result = successCallback(this.value)
						// result返回对象可能是基本类型或者promise
						// 是promise 判断成功失败返回, 除自身p以外，否则会循环调用
						// 当前获取不到p 所以需要异步执行处理等待p结果
						resolvePromise(result, resolve, reject, p)
						// resolve(resolve)
					} catch (e) {
						reject(e)
					}
				}, 0)
			}
			if (this.status === REJECTED) {
				setTimeout(() => {
					try {
						let result = failCallback(this.reason)
						resolvePromise(result, resolve, reject, p)
					} catch (e) {
						reject(e)
					}
					// resolve(resolve)
				}, 0)
			}
			//单个then处理
			// if (this.status === PENDING) {
			// 	this.successCallback = successCallback
			// 	this.failCallback = failCallback
			// }
			//多个then处理，需要用数组存储多个then回调函数
			if (this.status === PENDING) {
				this.successCallback.push(successCallback);
				this.failCallback.push(failCallback);
			}
		})
		return p
	}

	static all (promiseList) {
		let result = [];
		let doneTotal = 0;
		return new Promise((resolve, reject) => {
			function handleResultData (index, value) {
				result[index] = value;
				doneTotal ++;
				if (doneTotal === promiseList.length) resolve(result);
			}
			for (let index = 0; index < promiseList.length; index++) {
				const element = promiseList[index];
				if (element instanceof MyPromise) {
					element.then(value => handleResultData(index, value), reason => reject(reason));
				} else {
					handleResultData(index, element);
				}
			};
		})
	}

	static resolve (value) {
		if (value instanceof MyPromise) return value;
		return new MyPromise(resolve => resolve(value));
	}

	static reject (value) {
		if (value instanceof MyPromise) return value;
		return new MyPromise(resolve, reject => reject(value));
	}
}

function resolvePromise (x, resolve, reject, p) {
	if (x === p) {
		reject(new TypeError)
	}
	if (x instanceof MyPromise) {
		x.then(value => resolve(value), reason => reject(reason))
	} else {
		resolve(x)
	}

}

// module.exports = MyPromise;